package com.frank.loadinglibrary.special;

import com.frank.loadinglibrary.common.BallBeatLoadComponent;
import com.frank.loadinglibrary.common.BaseLoadingComponent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class SlackLoadingComponent extends BaseLoadingComponent implements Component.DrawTask {

    //静止状态
    private final int STATUS_STILL = 0;

    //加载状态
    private final int STATUS_LOADING = 1;

    //线条最大长度
    private final int MAX_LINE_LENGTH = 120;

    //线条最短长度
    private final int MIN_LINE_LENGTH = 40;

    //最大间隔时长
    private final int MAX_DURATION = 6000;

    //最小间隔时长
    private final int MIN_DURATION = 1000;

    private Paint mPaint;

    private int[] mColors = new int[]{0xB07ECBDA, 0xB0E6A92C, 0xB0D6014D, 0xB05ABA94};

    private int mWidth, mHeight;

    //动画间隔时长
    private int mDuration = MIN_DURATION;

    //线条总长度
    private int mEntireLineLength = MIN_LINE_LENGTH;

    //圆半径
    private int mCircleRadius;

    //所有动画
    private List<Animator> mAnimList = new ArrayList<>();

    //Canvas起始旋转角度
    private final int CANVAS_ROTATE_ANGLE = 60;

    //动画当前状态
    private int mStatus = STATUS_STILL;

    //Canvas旋转角度
    private int mCanvasAngle;

    //线条长度
    private float mLineLength;

    //半圆Y轴位置
    private float mCircleY;

    //第几步动画
    private int mStep;


    public SlackLoadingComponent(Context context) {
        this(context, null);
    }

    public SlackLoadingComponent(Context context, AttrSet attrSet) {
        super(context, attrSet, "");
        init();
    }

    public SlackLoadingComponent(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init();
    }

    @Override
    protected void stopAnimators() {
        reset();
    }

    @Override
    protected void startAnimators() {
        reset();
        start();
    }

    private void init() {
        setPaint();
        initData();
        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {
                if (autoStart)
                    startAnimators();
            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {
                stopAnimators();
            }
        });
        addDrawTask(this);
    }

    public void setPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        Color currentColor = new Color(mColors[0]);
        mPaint.setColor(currentColor);
        mPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
    }

    private void initData() {
        mCanvasAngle = CANVAS_ROTATE_ANGLE;
        mLineLength = mEntireLineLength;
        mCircleRadius = mEntireLineLength / 5;
        mPaint.setStrokeWidth(mCircleRadius * 2);
        mStep = 0;
    }


    private void drawCRLC(Canvas canvas, float startX, float startY, float stopX, float stopY, Paint paint, int rotate) {
        canvas.rotate(rotate, mWidth / 2, mHeight / 2);
        canvas.drawLine(startX, startY, stopX, stopY, paint);
        canvas.rotate(-rotate, mWidth / 2, mHeight / 2);
    }

    private void drawCR(Canvas canvas, float x, float y, Paint paint, int rotate) {
        canvas.rotate(rotate, mWidth / 2, mHeight / 2);
        canvas.drawCircle(x, y, mCircleRadius, paint);
        canvas.rotate(-rotate, mWidth / 2, mHeight / 2);
    }

    private void drawCRCC(Canvas canvas, float x, float y, Paint paint, int rotate) {
        canvas.rotate(rotate, mWidth / 2, mHeight / 2);
        canvas.drawCircle(x, y, mCircleRadius, paint);
        canvas.rotate(-rotate, mWidth / 2, mHeight / 2);
    }

    private void drawLC(Canvas canvas, float startX, float startY, float stopX, float stopY, Paint paint, int rotate) {
        canvas.rotate(rotate, mWidth / 2, mHeight / 2);
        canvas.drawLine(startX, startY, stopX, stopY, paint);
        canvas.rotate(-rotate, mWidth / 2, mHeight / 2);
    }

    /***
     * 四步动画：
     * 画布旋转及线条变化动画（Canvas Rotate Line Change）
     * 画布旋转动画（Canvas Rotate）
     * 画布旋转圆圈变化动画（Canvas Rotate Circle Change）
     * 线条变化动画（Line Change）
     * @param component
     * @param canvas
     */
    @Override
    public void onDraw(Component component, Canvas canvas) {
        mWidth = getWidth();
        mHeight = getHeight();
        switch (mStep % 4) {
            case 0:
                for (int i = 0; i < mColors.length; i++) {
                    mPaint.setColor(new Color(mColors[i]));
                    drawCRLC(canvas, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 - mLineLength, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mEntireLineLength, mPaint, mCanvasAngle + i * 90);
                }
                break;
            case 1:
                for (int i = 0; i < mColors.length; i++) {
                    mPaint.setColor(new Color(mColors[i]));
                    drawCR(canvas, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mEntireLineLength, mPaint, mCanvasAngle + i * 90);
                }

                break;

            case 2:
                for (int i = 0; i < mColors.length; i++) {
                    mPaint.setColor(new Color(mColors[i]));
                    drawCRCC(canvas, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mCircleY, mPaint, mCanvasAngle + i * 90);
                }

                break;

            case 3:
                for (int i = 0; i < mColors.length; i++) {
                    mPaint.setColor(new Color(mColors[i]));
                    drawLC(canvas, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mEntireLineLength, mWidth / 2 - mEntireLineLength / 2.2f, mHeight / 2 + mLineLength, mPaint, mCanvasAngle + i * 90);
                }
                break;
        }
    }

    /**
     * Animation1
     * 动画1
     * Canvas Rotate Line Change
     * 画布旋转及线条变化动画
     */

    private void startCRLCAnim() {
        Collection<Animator> animList = new ArrayList<>();
        AnimatorValue canvasRotateAnim = new AnimatorValue();

        canvasRotateAnim.setValueUpdateListener((animatorValue, v) -> {
            //ValueAnimator.ofInt(CANVAS_ROTATE_ANGLE + 0, CANVAS_ROTATE_ANGLE + 360);
            mCanvasAngle = (int) (CANVAS_ROTATE_ANGLE + 360 * v);
        });

        animList.add(canvasRotateAnim);


        AnimatorValue lineWidthAnim = new AnimatorValue();
        lineWidthAnim.setValueUpdateListener((animatorValue, v) -> {
            //ValueAnimator.ofFloat(mEntireLineLength, -mEntireLineLength)
            mLineLength = mEntireLineLength * Math.abs((1 - 2 * v));
            invalidate();
        });
        animList.add(lineWidthAnim);


        AnimatorGroup animatorGroup = new AnimatorGroup();
        animatorGroup.setDuration(mDuration);
        animatorGroup.runParallel(canvasRotateAnim, lineWidthAnim);
        animatorGroup.setCurveType(Animator.CurveType.LINEAR);
        animatorGroup.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
//                HiLog.debug(BallBeatLoadComponent.label, "eric", "动画1结束");
                if (mStatus == STATUS_LOADING) {
                    mStep++;
                    startCRAnim();
                }
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        animatorGroup.start();
        mAnimList.add(animatorGroup);

    }


    /**
     * Animation2
     * 动画2
     * Canvas Rotate
     * 画布旋转动画
     */
    private void startCRAnim() {
        AnimatorValue canvasRotateAnim = new AnimatorValue();
        canvasRotateAnim.setDuration(mDuration);
        canvasRotateAnim.setCurveType(Animator.CurveType.LINEAR);
        float angle = mCanvasAngle;
        canvasRotateAnim.setValueUpdateListener((animatorValue, v) -> {
            //ValueAnimator.ofInt(mCanvasAngle, mCanvasAngle + 180);
            mCanvasAngle = (int) (angle + 180 * v);
            invalidate();
        });


        canvasRotateAnim.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                HiLog.debug(BallBeatLoadComponent.label, "eric", "动画2结束");
                if (mStatus == STATUS_LOADING) {
                    mStep++;
                    startCRCCAnim();
                }
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        canvasRotateAnim.start();
        mAnimList.add(canvasRotateAnim);
    }


    /**
     * Animation3
     * 动画3
     * Canvas Rotate Circle Change
     * 画布旋转圆圈变化动画
     */
    private void startCRCCAnim() {
        Collection<Animator> animList = new ArrayList<>();
        AnimatorValue canvasRotateAnim = new AnimatorValue();
        float angle = mCanvasAngle;
        canvasRotateAnim.setValueUpdateListener((animatorValue, v) -> {
            //ValueAnimator.ofInt(mCanvasAngle, mCanvasAngle + 90, mCanvasAngle + 180);
            mCanvasAngle = (int) (mCanvasAngle + 90 + 90 * v);
        });
        canvasRotateAnim.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }
            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {

            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        animList.add(canvasRotateAnim);
        AnimatorValue circleYAnim = new AnimatorValue();

        circleYAnim.setValueUpdateListener((animatorValue, v) -> {
            //ValueAnimator.ofFloat(mEntireLineLength, mEntireLineLength / 4, mEntireLineLength);
            mCircleY = mEntireLineLength / 4 + Math.abs((1 - 2 * v) * (3 * mEntireLineLength / 4));
            invalidate();
        });
        animList.add(circleYAnim);


        AnimatorGroup animationGroup = new AnimatorGroup();
        animationGroup.setDuration(mDuration);
        animationGroup.runParallel(canvasRotateAnim, circleYAnim);
        animationGroup.setCurveType(Animator.CurveType.LINEAR);
        animationGroup.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                HiLog.debug(BallBeatLoadComponent.label, "eric", "动画3结束");
                if (mStatus == STATUS_LOADING) {
                    mStep++;
                    startLCAnim();
                }
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        animationGroup.start();
        mAnimList.add(animationGroup);
    }

    /**
     * Animation4
     * 动画4
     * Line Change
     * 线条变化动画
     */
    private void startLCAnim() {

        AnimatorValue lineWidthAnim = new AnimatorValue();

        lineWidthAnim.setDuration(mDuration);

        lineWidthAnim.setCurveType(Animator.CurveType.LINEAR);
        lineWidthAnim.setValueUpdateListener((animatorValue, v) -> {
            //ValueAnimator.ofFloat(mEntireLineLength - dp2px(getContext(), 1), -mEntireLineLength);
            mLineLength = (float) mEntireLineLength - 1 - (v * 2) * (mEntireLineLength * 2 + 0.5f);

            invalidate();

        });
        lineWidthAnim.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                HiLog.debug(BallBeatLoadComponent.label, "eric", "动画4结束");
                if (mStatus == STATUS_LOADING) {
                    mStep++;
                    startCRLCAnim();
                }
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        lineWidthAnim.start();
        mAnimList.add(lineWidthAnim);
    }

    public void setLineLength(float scale) {
        mEntireLineLength = (int) (scale * (MAX_LINE_LENGTH - MIN_LINE_LENGTH)) + MIN_LINE_LENGTH;
        reset();
    }


    public void setDuration(float scale) {
        mDuration = (int) (scale * (MAX_DURATION - MIN_DURATION)) + MIN_DURATION;
        reset();
    }


    public void start() {
        if (mStatus == STATUS_STILL) {
            mAnimList.clear();
            mStatus = STATUS_LOADING;
            startCRLCAnim();
        }
    }


    public void reset() {
        if (mStatus == STATUS_LOADING) {
            mStatus = STATUS_STILL;
            for (Animator anim : mAnimList) {
                anim.cancel();
            }
        }
        initData();
        invalidate();
    }
}
